/* C++11 STL容器  push/insert  =>  emplace新的方法
 *
 * 手写 emplace方法
 * */

#include <iostream>
using namespace std;

class Test{
public:
    Test(int a){
        cout<<"Test(int)"<<endl;
    }
    Test(int a,int b){
        cout<<"Test(int,int)"<<endl;
    }
    ~Test(){
        cout<<"~Test()"<<endl;
    }
    Test(const Test&){
        cout<<"Test(const Test&)"<<endl;
    }
    Test(Test&&){
        cout<<"Test(Test&&)"<<endl;
    }
};

//实现容器的空间配置器
template<typename T>
class MyAllocator{
public:
    //allocate deallocate
    //construct destroy
    T* allocate(size_t size){
        return (T*) malloc(size*sizeof (T));
    }

    template<typename ... Types>
    void construct(T* ptr,Types&&... args){
        //args只是一个参数，而且是个Test对象，T也是Test类型
        new (ptr) T(std::forward<Types>(args)...);
    }
};

template<typename T,typename Alloc=MyAllocator<T>>
class vector{
private:
    T* vec_;
    int size_;
    int idx_;
    Alloc allocator_;
public:
    vector():vec_(nullptr),size_(0),idx_(0){

    }
    //预留内存空间
    void reserve(size_t size){
        vec_=allocator_.allocate(size);
        size_=size;
    }

    //push_back
//    void push_back(const T& val){
//        allocator_.construct(vec_+idx_,val);
//        idx_++;
//    }
//    void push_back(T&& val){
//        allocator_.construct(vec_+idx_,std::move(val));
//        idx_++;
//    }

    template<typename Types>
    void push_back(Types&& val){
        allocator_.construct(vec_+idx_,std::forward<Types>(val));
        idx_++;
    }
    //1、引用折叠
    template<typename ... Types>
    void emplace_back(Types&& ... args){
        //不管是左值引用还是右值引用变量，它本身是个左值。
        //传递过程中要保持args的引用类型  =》 类型完美转发机制 forward
        allocator_.construct(vec_+idx_,std::forward<Types>(args)...);
        idx_++;
    }
};

int main(){
    Test t1(10);
    vector<Test> v;
    v.reserve(100);
    cout<<"-----------"<<endl;
    //直接插入对象，两个是没有区别的
    v.push_back(t1);
    v.emplace_back(t1);
    cout<<"-----------"<<endl;
    v.push_back(Test(20));
    v.emplace_back(Test(20));
    cout<<"-----------"<<endl;

    //给emplace传入Test对象构造所需要的参数，直接在容器底层构造对象即可
    v.emplace_back(20);
    v.emplace_back(30,40);
    cout<<"-----------"<<endl;

    /*
     map<int ,string> m;
     m.insert(make_pair(10,"wyx"));
     m.emplace(10,"wyx");   =>在map底层直接调用普通构造函数，生成一个pair对象
     * */
    return 0;
}
